home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / scheme / scm / wb1a1.lha / wb / check.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-29  |  16.7 KB  |  591 lines

  1. /* WB-tree File Based Associative String Data Base System.
  2.    Copyright (c) 1991, 1992, 1993 Holland Mark Martin
  3.  
  4. Permission to use, copy, modify, and distribute this software and its
  5. documentation for educational, research, and non-profit purposes and
  6. without fee is hereby granted, provided that the above copyright
  7. notice appear in all copies and that both that copyright notice and
  8. this permission notice appear in supporting documentation, and that
  9. the name of Holland Mark Martin not be used in advertising or
  10. publicity pertaining to distribution of the software without specific,
  11. written prior consent in each case.  Permission to incorporate this
  12. software into commercial products can be obtained from Jonathan
  13. Finger, Holland Mark Martin, 174 Middlesex Turnpike, Burlington, MA,
  14. 01803-4467, USA.  Holland Mark Martin makes no representations about
  15. the suitability or correctness of this software for any purpose.  It
  16. is provided "as is" without express or implied warranty.  Holland Mark
  17. Martin is under no obligation to provide any services, by way of
  18. maintenance, update, or otherwise. */
  19.  
  20. #include "sys.h"
  21. #include <stdio.h>
  22.  
  23. typedef unsigned char * STR;
  24. #define MAX_LEVELS   20
  25. #define MAP_SIZE     64000
  26. typedef unsigned long int BLOCK;
  27.  
  28. unsigned char free_map[65535];
  29.  
  30. char system_function = 'I';
  31. unsigned long int mon_disk_read = 0;
  32. unsigned long int mon_disk_write = 0;
  33. unsigned long int mon_os_file_read = 0;
  34. unsigned long int mon_interpreter = 0;
  35. unsigned long int mon_blink = 0;
  36. unsigned long int mon_symbol_table = 0;
  37. unsigned long int mon_term_io = 0;
  38.  
  39. int error_count;
  40. int fatal_error;
  41. int blkgc = 1;
  42. int follow_dirs = 1;
  43. unsigned long int blocks_marked; /* number of blocks in use by system */
  44. unsigned long int total_blocks_marked; /* number of blocks in use by system */
  45.  
  46. int set_block_used(blk_num)
  47. BLOCK blk_num;
  48. {
  49.  if ( (free_map[blk_num/8] >> (blk_num % 8)) & 1) return(0);
  50.  free_map[blk_num/8] |= (1 << (blk_num % 8));
  51.  return(1);
  52. }
  53.  
  54. int get_block_used(blk_num)
  55. BLOCK blk_num;
  56. {
  57.  if ( (free_map[blk_num/8] >> (blk_num % 8)) & 1) return(1);
  58.  return(0);
  59. }
  60.  
  61. struct disk_blk {
  62.          ENTRY *entry;
  63.          BLOCK blk_num;
  64.          BLOCK cont_ptr;
  65.          BLOCK tree_head;
  66.                  BLOCK act_blk_num;
  67.                  BLOCK act_tree_head;
  68.          long size;
  69.          int level;
  70.          int type;
  71.          int directory;
  72.                  unsigned char *block;
  73.                  unsigned char *current_pos;
  74.                  unsigned char *block_end;
  75.                  unsigned char current_name[256];
  76.                  int current_name_len;
  77.                  unsigned char last_block_name[256];
  78.                  int last_block_name_len;
  79.         };
  80.         
  81.  
  82.  
  83. typedef struct disk_blk DISK_BLK;
  84.  
  85. DISK_BLK disk_blocks[MAX_LEVELS];
  86. DISK_BLK temp_block;
  87.  
  88. void dspl_char(ch)
  89. int ch;
  90. {
  91.  if ((ch >= ' ') && (ch <= '~')) putchar(ch);
  92.   else printf("'%d'",ch);
  93. }
  94.  
  95. void dspl_string(string,size)
  96. STR string;
  97. int size;
  98. {
  99. while (size-- > 0) dspl_char(*string++);
  100. }
  101.  
  102. void path(level)
  103. int level;
  104. {
  105.  int i = 0;
  106.  while (i <= level)
  107.     {
  108.      printf("\n  LEVEL %d  BLOCK: %lu --> %lu",
  109.             disk_blocks[i].level,
  110.         disk_blocks[i].act_blk_num,
  111.             disk_blocks[i].cont_ptr);
  112.      printf("\n   NAME: ");
  113.      dspl_string(disk_blocks[i].current_name,
  114.                  disk_blocks[i].current_name_len);
  115.      i++;
  116.     }
  117.  if (++error_count >= 50) fatal_error = 1;
  118. }
  119.  
  120. int string_compare(name1,len1,name2,len2)
  121. /* returns 0 if equal 1 if first larger, 2 if second larger */
  122. STR name1,name2;
  123. int len1,len2;
  124. {
  125.  int max_len = min(len1,len2);
  126.  int len = 0;
  127.  while ( (len < max_len) && (name1[len] == name2[len]))  len++;
  128.  if (len < len2)
  129.      {
  130.       if (len == len1) return(2);
  131.        else if (name1[len] < name2[len]) return(2);
  132.        else return(1);
  133.      }
  134.   else if (len < len1) return(1);
  135.   else return(0);
  136. }
  137.  
  138. int cnv_string_to_long(s1b,s1e,i)
  139. STR s1b, s1e;
  140. unsigned long int *i;
  141. {
  142.  unsigned long int rslt = 0,rslt1 = 0;
  143.  while ( (s1b != s1e) && (*s1b >= '0') && (*s1b <= '9') )
  144.         {
  145.          if ((rslt = (rslt*10) + (*s1b++ - 48) ) < rslt1) return(0);
  146.          rslt1 = rslt;
  147.         }
  148.  *i = rslt;
  149.  return(1);
  150. }
  151.  
  152. int check_saf(nam,len)
  153. STR nam;
  154. int len;
  155. {
  156.  BLOCK head_blk_num = disk_blocks[0].act_blk_num;
  157.  BLOCK cont_ptr;
  158.  int err = 0;
  159.  STR ptr1,ptr2;
  160.  int blk_error = 0;
  161.  do {
  162.      blocks_marked++;
  163.      total_blocks_marked++;
  164.      if (disk_blocks[0].blk_num != disk_blocks[0].act_blk_num)
  165.       {
  166.        printf("\nBLOCK %lu HAS WRONG BLOCK ID, HEAD BLOCK %lu",
  167.           disk_blocks[0].act_blk_num,head_blk_num);
  168.        err++;
  169.       }
  170.      if (disk_blocks[0].tree_head != head_blk_num)
  171.       {
  172.        printf("\nBLOCK %lu HAS WRONG HEAD BLOCK, HEAD BLOCK %lu",
  173.           disk_blocks[0].act_blk_num,head_blk_num);
  174.        err++;
  175.       }
  176.      if (!set_block_used(disk_blocks[0].act_blk_num))
  177.       {
  178.        printf("\nSAF BLOCK %lu USED MULTIPLE TIMES, HEAD BLOCK %lu",
  179.           disk_blocks[0].act_blk_num,head_blk_num);
  180.        err++;
  181.       }
  182.      if (disk_blocks[0].type != seq_typ)
  183.       {
  184.        printf("\nBLOCK %lu NOT A SAF BLOCK, HEAD BLOCK %lu",
  185.           disk_blocks[0].act_blk_num,head_blk_num);
  186.        err++;
  187.       }
  188.      if (disk_blocks[0].level != '0')
  189.       {
  190.        printf("\nBLOCK %lu SAF not LEVEL 0, HEAD BLOCK %lu",
  191.           disk_blocks[0].act_blk_num,head_blk_num);
  192.        err++;
  193.       }
  194.      ptr1 = disk_blocks[0].block + blk_data_start;
  195.      ptr2 = ptr1 + disk_blocks[0].size;
  196.      while (ptr1 < ptr2) ptr1 += *ptr1 + 1;
  197.      if (ptr1 != ptr2)
  198.           {
  199.        printf("\nBLOCK %lu SAF SIZE ERROR, HEAD BLOCK %lu",
  200.           disk_blocks[0].act_blk_num,head_blk_num);
  201.        err++;
  202.           }
  203.      cont_ptr = disk_blocks[0].cont_ptr;
  204.     } while (!err && cont_ptr
  205.          && !(blk_error = read_block(cont_ptr,
  206.              &disk_blocks[0],  head_blk_num)));
  207.  if (blk_error)
  208.      {
  209.       printf("\nERROR READING SAF BLOCK %lu HEAD BLOCK %lu",cont_ptr,
  210.               head_blk_num);
  211.        err++;
  212.       }
  213.  return(err);
  214. }
  215.  
  216. int read_block(blk_num,dblock,head_block)
  217. BLOCK blk_num;
  218. DISK_BLK *dblock;
  219. BLOCK head_block;
  220. {
  221.  unsigned char *ptr1,*ptr2;
  222.  if (blk_num == 19551)
  223.    {
  224.     int i;
  225.     i = 0;
  226. }
  227.  dblock->block = ent_blk(dblock->entry);
  228.  dblock->act_tree_head = head_block;
  229.  dblock->act_blk_num = blk_num;
  230.  if (!(get_ent_copy(dblock->entry,1,blk_num))) return(1);
  231.  dblock->blk_num = str2long(dblock->block,blk_id_pos);
  232.  dblock->cont_ptr = str2long(dblock->block,blk_nxt_id_pos);
  233.  dblock->tree_head = str2long(dblock->block,blk_top_id_pos);
  234.  dblock->size = str2short(dblock->block,blk_end_pos)
  235.                  - blk_data_start;
  236.  dblock->level = dblock->block[blk_level_pos] - '0';
  237.  dblock->type = blk_typ(dblock->block);
  238.  if (dblock->type == 'D') dblock->directory = 'Y';
  239.   else dblock->directory = 'N';
  240.  ptr1 = &dblock->block[blk_data_start];
  241.  ptr2 = ptr1 + dblock->size;
  242.  return(0);
  243. }
  244.  
  245. int check_struct_level(dsk_blk_ind,next_block,start_name,start_name_len,
  246.               end_name,end_name_len,level)
  247.      int dsk_blk_ind;
  248.      BLOCK next_block;
  249.      STR start_name,end_name;
  250.      int start_name_len,end_name_len,level;
  251. {
  252.   STR ptr1,ptr2,ptr3,ptr4;
  253.   int errs = 0;
  254.   int i,j;
  255.   BLOCK block_num,next_block_num;
  256.   unsigned char *namebuf,*namebuf1;
  257.   int namelen,namelen1,err;
  258.   blocks_marked++;
  259.   total_blocks_marked++;
  260.   namebuf = &disk_blocks[dsk_blk_ind].last_block_name[0];
  261.   namelen = disk_blocks[dsk_blk_ind].last_block_name_len;
  262.   namebuf1 = &disk_blocks[dsk_blk_ind].current_name[0];
  263.   if (disk_blocks[dsk_blk_ind].blk_num
  264.                != disk_blocks[dsk_blk_ind].act_blk_num)
  265.        {
  266.     printf("\nBLOCK %lu HAS WRONG BLOCK ID, HEAD BLOCK %lu",
  267.            disk_blocks[dsk_blk_ind].act_blk_num,
  268.            disk_blocks[dsk_blk_ind].tree_head);
  269.            path(dsk_blk_ind);
  270.     err++;
  271.        }
  272.   if (disk_blocks[dsk_blk_ind].tree_head != disk_blocks[0].act_blk_num)
  273.       {
  274.        printf("\nBLOCK %lu HAS WRONG HEAD BLOCK, HEAD BLOCK %lu",
  275.           disk_blocks[dsk_blk_ind].act_blk_num,
  276.           disk_blocks[0].act_blk_num);
  277.            path(dsk_blk_ind);
  278.        err++;
  279.       }
  280.   if (disk_blocks[dsk_blk_ind].level != level)
  281.        {
  282.     printf("\n LEVEL FOR BLOCK IS %d BUT EXPECTED %d",
  283.            disk_blocks[dsk_blk_ind].level, level);
  284.     path(dsk_blk_ind);
  285.     return(++errs);
  286.        }
  287.   if (!set_block_used(disk_blocks[dsk_blk_ind].act_blk_num))
  288.         {
  289.      printf("\nBLOCK %lu USED MULTIPLE TIMES",
  290.         disk_blocks[dsk_blk_ind].act_blk_num);
  291.      path(dsk_blk_ind);
  292.      return(++errs);
  293.         }
  294.   if (disk_blocks[dsk_blk_ind].cont_ptr != next_block) {
  295.     printf("\n NEXT POINTER FOR BLOCK IS %lu BUT EXPECTED %lu",
  296.        disk_blocks[dsk_blk_ind].cont_ptr, next_block);
  297.     path(dsk_blk_ind);
  298.     return(++errs);
  299.   }
  300.   ptr1 = disk_blocks[dsk_blk_ind].block + blk_data_start + 1;
  301.   i = *ptr1++;
  302.   namelen1 = 0; while (i-- > 0) namebuf1[namelen1++] = *ptr1++;
  303.   disk_blocks[dsk_blk_ind].current_name_len = namelen1;
  304.   if (namelen && string_compare(namebuf,namelen,namebuf1,namelen1) != 2)
  305.      {
  306.       printf("\nFIRST ENTRY SMALLER THAN LAST ENTRY IN PREV BLOCK");
  307.       printf("\n PREV NAME: ");
  308.       dspl_string(namebuf,namelen);
  309.       printf("\n CURR NAME: ");
  310.       dspl_string(namebuf1,namelen1);
  311.       path(dsk_blk_ind);
  312.      }
  313.   if (string_compare(start_name,start_name_len,namebuf1,namelen1) == 1)
  314.       {
  315.        printf("\nFIRST ENTRY SMALLER THAN INDEX SPLITKEY");
  316.        printf("\n SPLIT KEY: ");
  317.        dspl_string(start_name,start_name_len);
  318.        printf("\n CURR NAME: ");
  319.        dspl_string(namebuf1,namelen1);
  320.        path(dsk_blk_ind);
  321.       }
  322.   ptr1 = disk_blocks[dsk_blk_ind].block + blk_data_start;
  323.   ptr2 = ptr1 + disk_blocks[dsk_blk_ind].size;
  324.   while (ptr1 < ptr2) /* check block size */
  325.       {
  326.        ptr1++;
  327.        ptr1 += *ptr1 + 1;
  328.        if (ptr1 < ptr2)  /* not at splitkey */
  329.           {
  330.            ptr1 += *ptr1 + 1;
  331.           }
  332.       }
  333.   if (ptr1 != ptr2)
  334.       {
  335.        printf("\nBLOCK %lu SIZE ERROR, HEAD BLOCK %lu",
  336.            disk_blocks[dsk_blk_ind].act_blk_num,
  337.            disk_blocks[dsk_blk_ind].tree_head);
  338.        err++;
  339.       }
  340.   ptr1 = disk_blocks[dsk_blk_ind].block + blk_data_start;
  341.   while ((ptr1 < ptr2) && !fatal_error) {
  342.     namelen1 = *ptr1++;
  343.     i = *ptr1++;
  344.     ptr3 = ptr1 + i;
  345.     ptr3 += *ptr3 + 1;
  346.     j = i;
  347.     ptr4 = ptr1;
  348.     while (j-- > 0) namebuf1[namelen1++] = *ptr4++;
  349.     disk_blocks[dsk_blk_ind].current_name_len = namelen1;
  350.     if (string_compare(namebuf,namelen,namebuf1,namelen1) != 2
  351.     && namelen) {
  352.       printf("\nCOLLATION ERROR");
  353.       path(dsk_blk_ind);
  354.       return(++errs);
  355.     }
  356.     if (ptr3 < ptr2)         /* not on last (splitkey) entry */
  357.      {
  358.       block_num = str2long(ptr1, i + 1);
  359.       ptr1 = ptr3 + *(ptr3+1) + 3;
  360.       if (disk_blocks[dsk_blk_ind].level != 0) {
  361.     next_block_num = 0;
  362.     if (ptr1 < ptr2) next_block_num = str2long(ptr1,0);
  363.     else if (disk_blocks[dsk_blk_ind].cont_ptr)
  364.       if (get_ent_copy(temp_block.entry,1,
  365.                disk_blocks[dsk_blk_ind].cont_ptr)) {
  366.         ptr1 = ent_blk(temp_block.entry) + blk_data_start + 1;
  367.         ptr4 = ent_blk(temp_block.entry)
  368.           + str2short(ent_blk(temp_block.entry),blk_end_pos);
  369.         ptr1 += *ptr1 + 1;
  370.         i = *ptr1++;
  371.         if (ptr1 + i + 1 < ptr4) next_block_num = str2long(ptr1,0);
  372.       }
  373.     if (read_block(block_num,&disk_blocks[dsk_blk_ind+1],
  374.                disk_blocks[dsk_blk_ind].tree_head)) {
  375.       printf("\nERROR READING BLOCK %lu",block_num);
  376.       path(dsk_blk_ind);
  377.     }
  378.     else errs += check_struct_level(dsk_blk_ind + 1,next_block_num,
  379.                     namebuf,namelen,namebuf1,namelen1,
  380.                     disk_blocks[dsk_blk_ind].level-1);
  381.       }
  382.       namelen = 0;
  383.       while (namelen < namelen1) {
  384.     namebuf[namelen] = namebuf1[namelen];
  385.     namelen++;
  386.       }
  387.       disk_blocks[dsk_blk_ind].last_block_name_len = namelen;
  388.     }
  389.     else if (string_compare(end_name,end_name_len,namebuf1,namelen1) != 0)
  390.       /* on last (splitkey) entry */
  391.       {
  392.     printf("\nSPLIT KEY MISMATCH");
  393.     path(dsk_blk_ind);
  394.     return(++errs);
  395.       }
  396.     ptr1 = ptr3;
  397.   }
  398.   return(errs);
  399. }
  400.  
  401. void check_struct(blk_num, name, len, dirdepth)
  402. BLOCK blk_num;
  403. STR name;
  404. int len;
  405. int dirdepth;
  406. {
  407.   unsigned char start[1],end[3];
  408.   unsigned long int blocks_in_directory = 0;
  409.   int directory = 0;
  410.   /*  reset_disk_blocks(); */
  411.   int i = 0;
  412.   while (i < MAX_LEVELS) {
  413.     disk_blocks[i].last_block_name_len = 0;
  414.     disk_blocks[i].current_name_len = 0;
  415.     i++;
  416.   }
  417.   if (read_block(blk_num,&disk_blocks[0],blk_num)) {
  418.     printf("\nERROR READING BLOCK");
  419.     ++error_count;
  420.     return;
  421.   }
  422.   if (!root_P(disk_blocks[0].block)) {
  423.     printf("\nNOT A ROOT BLOCK\n");
  424.     ++error_count;
  425.     return;
  426.   }
  427.   if (blk_typ_P(disk_blocks[0].block, dir_typ)) {
  428.     printf("\n%*.c",dirdepth,' ');
  429.     dspl_string(name, len);
  430.     printf(" -> block number: %lu",blk_num);
  431.     directory = 1;
  432.   }
  433.   blocks_marked = 0;
  434.   end[0] = 255;
  435.   end[1] = disk_blocks[0].level + '0';
  436.   if (disk_blocks[0].type == seq_typ) /* SEQUENTIAL FILE */
  437.       {
  438.        error_count += check_saf(name,len);
  439.        blocks_in_directory += blocks_marked;
  440.       }
  441.   else if (!(i=check_struct_level(0,0L,start,0,end,2,disk_blocks[0].level)) &&
  442.        follow_dirs &&
  443.        (blk_typ_P(disk_blocks[0].block, dir_typ))) {
  444.     unsigned char key[256], val[256];
  445.     int klen=0, vlen;
  446.     HAND han;
  447.     bt_open(1,blk_num,&han,0);
  448.     blocks_in_directory += blocks_marked;
  449.     while ((klen = bt_next(&han, key, klen, key)) > 0)
  450.      {
  451.       if (((vlen = bt_get(&han, key, klen, val)) >= 5) && (4 == val[0]))
  452.         {
  453.          blocks_marked = 0;
  454.          check_struct(str2long(val,1), key, klen, 1+dirdepth);
  455.          blocks_in_directory += blocks_marked;
  456.         }
  457.       }
  458.   }
  459.   else  { error_count += i; blocks_in_directory += blocks_marked; }
  460.   blocks_marked = blocks_in_directory;
  461.   if (directory)
  462.      { printf("\n%*.c%lu BLOCKS",dirdepth,' ',blocks_in_directory); }
  463. }
  464.  
  465. BLOCK nextnum(hand, key, klen)
  466.      HAND *hand;
  467.      STR key;
  468.      int klen;
  469. {
  470.   klen = bt_next(hand,key,klen,key);
  471.   if (klen <= 0) return 0;
  472.   else if (klen != 4) {
  473.     printf("BAD SIZE KEY IN FREELIST\n");
  474.     exit(2);
  475.   }
  476.   return str2long(key,0);
  477. }
  478.  
  479. int main( argc, argv )
  480. int argc;
  481. char *argv[];
  482. {
  483.   unsigned int i = 0;
  484.   BLOCK blk_num;
  485.   if (argc < 2) {
  486.     printf("NO FILE\n");
  487.     exit(0);
  488.   }
  489.   if (argc > 2) {
  490.     char *ptr1,*ptr = &argv[2][0];
  491.     ptr1 = ptr;
  492.     while ( (*ptr1 >= '0') && (*ptr1 <= '9')) ptr1++;
  493.     if (*ptr1) {
  494.       printf("NOT A NUMBER\n");
  495.       exit(0);
  496.     }
  497.     if (!cnv_string_to_long(ptr,ptr1,&blk_num)) {
  498.       printf("NUMBER TOO LARGE\n");
  499.       exit(0);
  500.     }
  501.     blkgc = 0;
  502.     follow_dirs = 0;
  503.   }
  504.   else blk_num = 0;
  505.   init_filesystem();
  506.   if (open_seg(1,argv[1],2)<0) {
  507.     printf("COULDN NOT OPEN SEGMENT %s\n", argv[1]);
  508.     exit(0);
  509.   }
  510.   while ( (i < MAX_LEVELS) && (disk_blocks[i].entry = allocate_ent()) ) i++;
  511.   if ( i < MAX_LEVELS || !(temp_block.entry = allocate_ent()) ) {
  512.     printf("UNABLE TO ALLOCATE ENOUGH ENTRIES\n");
  513.     exit(0);
  514.   }
  515.   i = 0; while (i < MAP_SIZE) free_map[i++] = 0;
  516.   error_count = 0;
  517.   fatal_error = 0;
  518.   total_blocks_marked = 0;
  519.   check_struct(blk_num, "", 0, 1);
  520.   printf("\n%lu BLOCKS MARKED IN USE",total_blocks_marked);
  521.   if (error_count) {
  522.     printf("\n %d ERRORS\n",error_count);
  523.     return 1;
  524.   }
  525.   printf("\nNO STRUCTURE ERRORS FOUND\n");
  526.   if (!blkgc) return 0;
  527.   {
  528.     HAND han;
  529.     unsigned char key[5*4], tmp[4];
  530.     BLOCK used=0, num_freed=0, num_collected=0, fnum;
  531.     int flc_image_len, i, j=0;
  532.     bt_open(1,0L,&han,0);
  533.     if (4 != bt_get(&han,"USED",4,key)) exit(2);
  534.     used = str2long(key,0);
  535.     flc_image_len = bt_get(&han, "FLC",3,key);
  536.  
  537.     bt_open(1,2L,&han,0);
  538.     if (0 > (flc_image_len))
  539.       flc_image_len = 0;
  540.     i = -4+(flc_image_len);
  541.     while (0 <= i) {
  542.       fnum = str2long(key, i);
  543. /*      printf("\n %lu: used %d FREELIST %d\n",
  544.          fnum,get_block_used(fnum),bt_get(&han, &key[i], 4, tmp)); */
  545.       if (!(get_block_used(fnum) || (0 < bt_get(&han, &key[i], 4, tmp)))) {
  546.     seg_flc(1)[j++] = str2long(key, i);
  547.     set_block_used(fnum);
  548.       }
  549.       i = -4+(i);
  550.     }
  551.     seg_set_flc_len(1, j);
  552.  
  553.     /* scan the first time for blocks which shouldn't be there. */
  554.     /* This is so that we won't use bad blocks to extend FREELIST */
  555.     blk_num = nextnum(&han, key, 0);
  556.     while (blk_num) {
  557.       if (get_block_used(blk_num)) {
  558.     printf("\nA block in the FREELIST is acutally being used: %lu", blk_num);
  559.     num_freed++;
  560.     flush_flc(1,flc_len-5);    /* make sure there is room in flc for any deleted blocks */
  561.     bt_rem(&han,key,4,0L);
  562.       }
  563.       else set_block_used(blk_num); /* so that stuff on the FREELIST is marked. */
  564.       blk_num = nextnum(&han, key, 4);
  565.     }
  566.     blk_num=0;
  567.     /* add all of bitmap is that is unused. */
  568.     printf("\n    reclaiming unused blocks:");
  569.     while (used > ++blk_num)
  570.       if (!get_block_used(blk_num)) {
  571.     printf(" %lu", blk_num);
  572.     num_collected++;
  573.     flc_fill(1); /* make sure there are enought blks in flc for splits */
  574.     flush_flc(1,flc_len-2);    /* make sure there is room in flc for a collected block */
  575.     lck(seg_lck(1));
  576.     seg_flc(1)[seg_flc_len(1)]=blk_num;
  577.     seg_set_flc_len(1,1+seg_flc_len(1));
  578.     unlck(seg_lck(1));
  579.       }
  580.     close_seg(1,1);        /* need to close it because changes have been made. */
  581.     printf("\nFREELIST: %lu blocks removed; %lu blocks added.\n",num_freed, num_collected);
  582.   }
  583.   return 0;
  584. }
  585.  
  586. void display_disk_statistics(b, t, r, w)
  587.      BLOCK b;
  588.      char t;
  589.      unsigned long r,w;
  590. {}
  591.